package joc.transformer;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import javassist.CtClass;
import joc.Cache;
import joc.contract.Contract;

public abstract class ClassTransformer {
	protected Logger logger = Logger.getLogger(getClass());
	protected Transformer transformer;
	
	public ClassTransformer(Transformer transformer) {
		this.transformer = transformer;
	}

	public abstract void transform(CtClass clazz) throws Exception;
	
	public List<Method> getContractMethodsWithAnnotation(Contract contract, Class<?>... annotationClasses) {
		List<Method> methods = new ArrayList<Method>();
		for (Method contractMethod : contract.getClass().getMethods()) {
			for (Class<?> annotationClass : annotationClasses) {
				@SuppressWarnings("unchecked")
				Class<? extends Annotation> annotationClassCasted = (Class<? extends Annotation>) annotationClass;
				Annotation methodAnnotation = contractMethod.getAnnotation(annotationClassCasted);
				if (methodAnnotation != null) {
					methods.add(contractMethod);
				}
			}
		}
		return methods;
	}
	
	public String getContractCallString(Method contractMethod, Contract contract, Annotation annotation, String... moreArgs) throws Exception {
		long methodKey = Cache.saveMethod(contractMethod);
		long annotationKey = Cache.saveAnnotation(annotation);
		String callString = "joc.Invoker#callContract(" + contract.getAnnotationClass().getName() + ".class, joc.Cache#getMethod(" + methodKey + "L), new Object[] { joc.Cache#getAnnotation(" + annotationKey + "L)" + joinStringDelimiterInFront(moreArgs, ", ") + " });";
		logger.info("callString: " + callString);
		return callString;
	}
	
	protected String joinStringDelimiterInFront(String[] parts, String delimiter) {
		StringBuilder sb = new StringBuilder();
		for (String part : parts) {
			sb.append(delimiter).append(part);
		}
		return sb.toString();
	}
}
